#include <stdio.h>
#include <stdlib.h>

#include "errormanager.h"

#include "messages.h"
// #include "outputAPI.h"
#include "swmm_output.h"

// 动态库操作库函数
#ifdef _WIN32
	#include <Windows.h>
#else
	#include <dlfcn.h>
#endif
//#define F_OFF _off64_t
// #ifdef WINDOWS
#ifdef _WIN32
    /*#define F_OFF off64_t      */
	#ifdef __MINGW32__
		#define F_OFF _off64_t
	#else
    	#define F_OFF __int64
	#endif
#else
    #define F_OFF off_t
#endif
// define fseeko64 in different platform
// #ifdef WINDOWS
#ifdef _WIN32
    #ifdef __MINGW32__
       int (*fseeko64_)(FILE*, F_OFF, int) = &fseeko64;
    #else
        int (*fseeko64_)(FILE*, F_OFF, int) = &_fseeki64;
    #endif
#else
     int (*fseeko64_)(FILE*, F_OFF, int) = &fseeko;
#endif

int main(int argc, char* argv[]){
	
// 目的：读取out文件中指定点的时间序列结果
// argv1：输出文件路径
// argv2：要素类型，可从SMO_subcatch, SMO_node, SMO_link, 
//        SMO_sys, SMO_pollut中选择
// Example: get_element_index "trace_J24.out" 
	// 输出文件路径
	char path[MAXFILENAME];
	strcpy(path, argv[1]);
	char elementType[10];
	strcpy(elementType, argv[2]);
	SMO_elementType elementType_enum;

	// get_elementName 变量
	int errcode=0;
	char *elementName;
	int elementLength;

	printf("Output file path: %s\n",path);

	// 处理动态库文件 --------------------------------------------------------------
	// 导入库文件
	#ifdef _WIN32
		HMODULE module = LoadLibrary("libswmmoutputapi.dll");
	#else
		void* module = dlopen("libswmmoutputapi.so", RTLD_LAZY);
	#endif
	if (module == NULL){
		printf("Failed to load dll\n");
	}
	#ifdef _WIN32
	// 定义SMO_open函数，并指向dll中的对应函数，打开文件
	typedef int(*dll_SMO_open)(SMO_Handle*, const char*);
	dll_SMO_open SMO_open =
		(dll_SMO_open)GetProcAddress(module, "SMO_open");
	// 定义SMO_getProjectSize函数，并指向dll中的对应函数，获取工程大小
	typedef int(*dll_SMO_getProjectSize)(SMO_Handle* smoapi,
		    int **code, int* count);
	dll_SMO_getProjectSize SMO_getProjectSize =
		(dll_SMO_getProjectSize)GetProcAddress(module, "SMO_getProjectSize");
	// 获取要素名称，并和index对应
	typedef int(*dll_SMO_getElementName)(SMO_Handle* smoapi, SMO_elementType type,
		int elementIndex, char **elementName, int *size);
	dll_SMO_getElementName SMO_getElementName =
		(dll_SMO_getElementName)GetProcAddress(module, "SMO_getElementName");
	// 定义SMO_getNodeSeries函数，读取时间序列结果
	typedef int(*dll_SMO_getNodeSeries)(SMO_Handle* smoapi, int nodeIndex, SMO_nodeAttribute attr,
					    int startPeriod, int endPeriod, float **outValueArray, int *length);
	dll_SMO_getNodeSeries SMO_getNodeSeries =
		(dll_SMO_getNodeSeries)GetProcAddress(module, "SMO_getNodeSeries");
	// SMO_getUnits，获取单位
	typedef int(*dll_SMO_getUnits)(SMO_Handle* smoapi, int **unitFlag, int *length);
	dll_SMO_getUnits SMO_getUnits =
		(dll_SMO_getUnits)GetProcAddress(module, "SMO_getUnits");
	#else
		int(*SMO_open)(SMO_Handle*, const char*) =
			dlsym(module, "SMO_open");
		int(*SMO_getProjectSize)(SMO_Handle* smoapi, int **code, int* count) =
			dlsym(module, "SMO_getProjectSize");
		int(*SMO_getElementName)(SMO_Handle* smoapi, SMO_elementType type,
								int elementIndex, char **elementName, int *size) =
			dlsym(module, "SMO_getElementName");
		int(*SMO_getNodeSeries)(SMO_Handle* smoapi, int nodeIndex, SMO_nodeAttribute attr,
					    		int startPeriod, int endPeriod, float **outValueArray, int *length) =
			dlsym(module, "SMO_getNodeSeries");
		int(*SMO_getUnits)(SMO_Handle* smoapi, int **unitFlag, int *length) =
			dlsym(module, "SMO_getUnits");
	#endif

	//
	// 开始读取 -------------------------------------------------------------------------------
	// 初始化文件指针
	// SMO_Handle* smoapi = (SMO_Handle*)malloc(sizeof(SMO_Handle)); 
	SMO_Handle smoapi; 
	SMO_init(&smoapi);
	// 打开输出文件
	int errBEM = SMO_open(smoapi, path);
	if (errBEM != 0)
	{
		printf("Err code: %i\n", errBEM);
		return -1;
	}
	

	// 输出要素的数量
	int **elementCount = (int **)malloc(sizeof(int *));
	// get subcatch, node, link counts
	// elementCount 是数组指针
	int length;
	SMO_getProjectSize(smoapi, elementCount, &length);
	int n_subcatch = (*elementCount)[0];
	int n_node = (*elementCount)[1];
	int n_link = (*elementCount)[2];
	int n_sys = (*elementCount)[3];
	int n_pollut = (*elementCount)[4];
	printf("Subcatch Count: %d\n", n_subcatch);
	printf("Node Count: %d\n", n_node);
	printf("Link Count: %d\n", n_link);
	printf("Sys Count: %d\n", n_sys);
	printf("Pollutes Count: %d\n", n_pollut);
	free(elementCount);

	#ifdef DEBUG
	// SMO_elementType elementType = node;
	int elementIndex = 1;
	// char **elementName;
	// char **elementName = (char **)malloc(sizeof(char **));
	printf("Node index: %d\n", elementIndex);
	// errcode = SMO_getElementName(smoapi, elementType, elementIndex, elementName, length);
	// printf("Addr of elementName: %p\n", elementName);
	errcode = SMO_getElementName(smoapi, 1, 1, &elementName, &elementLength);
	printf("get error code: %d\n", errcode);
	printf("Node name: %s\n", elementName);
	printf("end\n");
	#endif

	int max_elementCount;
	if (strcmp(elementType,"SMO_subcatch") == 0)
	{
		max_elementCount = n_subcatch;
		elementType_enum = SMO_subcatch;
	}
	else if (strcmp(elementType,"SMO_node") == 0)
	{
		max_elementCount = n_node;
		elementType_enum = SMO_node;
	}
	else if (strcmp(elementType,"SMO_link") == 0)
	{
		max_elementCount = n_link;
		elementType_enum = SMO_link;
	}
	else if (strcmp(elementType,"SMO_sys") == 0)
	{
		max_elementCount = n_sys;
		elementType_enum = SMO_sys;
	}
	else if (strcmp(elementType,"SMO_pollut") == 0)
	{
		max_elementCount = n_pollut;
		elementType_enum = SMO_pollut;
	}
	else
	{
		printf("Unkown element type!\n");
		return -1;
	}
	
	int n_element;
	for (n_element = 0; n_element < max_elementCount; n_element ++)
		{
			errcode = SMO_getElementName(smoapi, elementType_enum,
						n_element, &elementName, &elementLength);
			printf("Element Name %s, index is %d\n",elementName, n_element);
		} 

	// 关闭文件
	SMO_close(&smoapi);
	// free(smoapi);
	// SMO_getNodeSeries
	FreeLibrary(module);

	return 0;
}
